/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include "cmsis_os2.h"
#include "flower.h"
#include "iot_errno.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "iot_i2c.h"
#include "iot_i2c_ex.h"
#include "iot_adc.h"
#include "iot_pwm.h"
#include "iot_demo_def.h"

#define FLOWER_MOTOR_STATUS_0 0
#define FLOWER_MOTOR_STATUS_1 1
#define FLOWER_MOTOR_GPIO_5 5
#define FLOWER_MOTOR_GPIO_0 0
#define FLOWER_MOTOR_GPIO_1 1
#define FLOWER_MOTOR_GPIO_10 10
#define FLOWER_MOTOR_GPIO_9 9
#define WIFI_IOT_I2C_IDX_1 1
#define WIFI_IOT_I2C_IDX_0 0
#define IOT_ADC_CHANNEL_6  6

#define WIFI_IOT_IO_FUNC_GPIO_8_PWM1_OUT 5

#define FAN_SPEED_LEVEL_0 0
#define FAN_SPEED_LEVEL_1 1
#define FAN_SPEED_LEVEL_2 2
#define FAN_SPEED_LEVEL_3 3
#define FAN_SPEED_LEVEL_4 4
#define CURTAIN_MOTOR_GPIO_IDX 8
#define CN_MAIN_FAN_PWM1OUT 1
#define CN_MAIN_FAN_FRE  4000

#define CN_MAIN_LED_GPIO_FUNC IOT_GPIO_FUNC_GPIO_14_PWM5_OUT
#define CN_MAIN_LED_GPIO  14
#define CN_MAIN_LED_PWD5OUT 5
#define CN_MAIN_LED_FRE  4000

#define SHT30_Addr 0x44
#define BH1750_ADDR 0x23

/***************************************************************
* 函数名称: E53IA1_SetMainLed
* 说    明: 启动E53IA1_SetMainLed
* 参    数: int status, int dutyCycle
* 返 回 值: dutyCycle     //光的亮度与光照强度无关
***************************************************************/
int E53IA1_SetMainLed(int status, int dutyCycle)
{
    int ret = 0;
    if(dutyCycle == 100)
    {dutyCycle = 99;}
    if (status == CN_BOARD_SWITCH_ON && dutyCycle != 0 ) {
        ret = IoTPwmStart(CN_MAIN_LED_PWD5OUT, dutyCycle, CN_MAIN_LED_FRE);
    } else {
        ret = IoTPwmStop(CN_MAIN_LED_PWD5OUT);
    }

    RaiseLog(LOG_LEVEL_INFO, "status=%d, dutyCycle=%d, ret = %d", status, dutyCycle, ret);

    return 0;
}


/***************************************************************
* 函数名称: Init_BH1750
* 说    明: 写命令初始化BH1750
* 参    数: 无
* 返 回 值: 无
***************************************************************/
static int InitBH1750(void)
{
    int ret;
    uint8_t send_data[1] = {0x01};
    ret = IoTI2cWrite(WIFI_IOT_I2C_IDX_1, (BH1750_ADDR << 1) | 0x00, send_data, 1);
    if (ret != 0) {
        printf("===== Error: I2C write ret = 0x%x! =====\r\n", ret);
        return -1;
    }
    return 0;
}

/***************************************************************
* 函数名称: Start_BH1750
* 说    明: 启动BH1750
* 参    数: 无
* 返 回 值: 无
***************************************************************/
static int StartBH1750(void)
{
    int ret;
    uint8_t send_data[1] = {0x10};
    ret = IoTI2cWrite(WIFI_IOT_I2C_IDX_1, (BH1750_ADDR << 1) | 0x00, send_data, 1);
    if (ret != 0) {
        printf("===== Error: I2C write ret = 0x%x! =====\r\n", ret);
        return -1;
    }
    return 0;
}
/***************************************************************
* 函数名称: SHT30_reset
* 说    明: SHT30复位
* 参    数: 无
* 返 回 值: 无
***************************************************************/
void SHT30_reset(void)
{
    uint8_t send_data[2] = {0x30, 0xA2};
    IoTI2cWrite(WIFI_IOT_I2C_IDX_0, (SHT30_Addr << 1) | 0x00, send_data, 2);
}

/***************************************************************
* 函数名称: Init_SHT30
* 说    明: 初始化SHT30，设置测量周期
* 参    数: 无
* 返 回 值: 无
***************************************************************/
int Init_SHT30(void)
{
    uint8_t send_data[2] = {0x22, 0x36};
    return IoTI2cWrite(WIFI_IOT_I2C_IDX_0, (SHT30_Addr << 1) | 0x00, send_data, 2);
}

/***************************************************************
* 函数名称: SHT3x_CheckCrc
* 说    明: 检查数据正确性
* 参    数: data：读取到的数据
                        nbrOfBytes：需要校验的数量
                        checksum：读取到的校对比验值
* 返 回 值: 校验结果，0-成功        1-失败
***************************************************************/
static uint8_t SHT3x_CheckCrc(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum)
{

    uint8_t crc = 0xFF;
    uint8_t bit = 0;
    uint8_t byteCtr;
    const int16_t POLYNOMIAL = 0x131;
    // calculates 8-Bit checksum with given polynomial
    for (byteCtr = 0; byteCtr < nbrOfBytes; ++byteCtr)
    {
        crc ^= (data[byteCtr]);
        for (bit = 8; bit > 0; --bit)
        {
            if (crc & 0x80)
                crc = (crc << 1) ^ POLYNOMIAL;
            else
                crc = (crc << 1);
        }
    }

    if (crc != checksum)
        return 1;
    else
        return 0;
}

/***************************************************************
* 函数名称: SHT3x_CalcTemperatureC
* 说    明: 温度计算
* 参    数: u16sT：读取到的温度原始数据
* 返 回 值: 计算后的温度数据
***************************************************************/
static float SHT3x_CalcTemperatureC(uint16_t u16sT)
{

    float temperatureC = 0;

    u16sT &= ~0x0003;

    temperatureC = (175 * (float)u16sT / 65535 - 45);

    return temperatureC;
}

/***************************************************************
* 函数名称: SHT3x_CalcRH
* 说    明: 湿度计算
* 参    数: u16sRH：读取到的湿度原始数据
* 返 回 值: 计算后的湿度数据
***************************************************************/
static float SHT3x_CalcRH(uint16_t u16sRH)
{

    float humidityRH = 0;

    u16sRH &= ~0x0003;

    humidityRH = (100 * (float)u16sRH / 65535);

    return humidityRH;
}

static int InitMotor()
{
/***************************************************************
* 说    明: 抽水机接口初始化
***************************************************************/
    // 设置GPIO_4的复用功能为普通GPIO
    IoTGpioSetFunc(FLOWER_MOTOR_GPIO_5, IOT_GPIO_FUNC_GPIO_5_GPIO);
    // 设置GPIO_4为输出模式
    IoTGpioSetDir(FLOWER_MOTOR_GPIO_5, IOT_GPIO_DIR_OUT);
    IoTGpioSetOutputVal(FLOWER_MOTOR_GPIO_5,FLOWER_MOTOR_STATUS_1);

/***************************************************************
* 说    明: 风扇  GPIO_8 初始化
***************************************************************/
    IoTGpioInit(CURTAIN_MOTOR_GPIO_IDX);
    IoTGpioSetFunc(CURTAIN_MOTOR_GPIO_IDX, WIFI_IOT_IO_FUNC_GPIO_8_PWM1_OUT);
    IoTGpioSetDir(CURTAIN_MOTOR_GPIO_IDX, IOT_GPIO_DIR_OUT);
    IoTPwmInit(CN_MAIN_FAN_PWM1OUT);
/***************************************************************
* 说    明: 补光灯  GPIO_14 初始化
***************************************************************/  
    IoTGpioInit(CN_MAIN_LED_GPIO);
    IoTGpioSetFunc(CN_MAIN_LED_GPIO, CN_MAIN_LED_GPIO_FUNC);
    IoTGpioSetDir(CN_MAIN_LED_GPIO, IOT_GPIO_DIR_OUT);
    IoTPwmInit(CN_MAIN_LED_PWD5OUT);
    return 0;
}

static int InitAirSensor()
{
    
/***************************************************************
* 说    明: E53_IA1  GPIO_0/_1  初始化 Init_BH1750
***************************************************************/
    // GPIO_0复用为I2C1_SDA
    if (IoTGpioSetFunc(FLOWER_MOTOR_GPIO_0, IOT_GPIO_FUNC_GPIO_0_I2C1_SDA) != 0) {
        RaiseLog(LOG_LEVEL_ERR, "IoTGpioSetFunc IOT_GPIO_FUNC_GPIO_0_I2C1_SDA failed! \n");
        return -1;
    }

    // GPIO_1复用为I2C1_SCL
    if (IoTGpioSetFunc(FLOWER_MOTOR_GPIO_1, IOT_GPIO_FUNC_GPIO_1_I2C1_SCL) != 0) {
        RaiseLog(LOG_LEVEL_ERR, "IoTGpioSetFunc IOT_GPIO_FUNC_GPIO_1_I2C1_SCL failed! \n");
        return -1;
    }
    // baudrate: 400kbps
        if (IoTI2cInit(WIFI_IOT_I2C_IDX_1, 400000) != 0) {
        RaiseLog(LOG_LEVEL_ERR, "IoTI2cInit failed! \n");
        return -1;
    }

        if (InitBH1750() != 0) {
        RaiseLog(LOG_LEVEL_ERR, "Init_BH1750 failed! \n");
        return -1;
    }
/***************************************************************
* 说    明: FLOWER  GPIO_10/_9  初始化  Init_SHT30
***************************************************************/
    // GPIO_10复用为I2C0_SDA
    if (IoTGpioSetFunc(FLOWER_MOTOR_GPIO_10, IOT_GPIO_FUNC_GPIO_10_I2C0_SDA) != 0) {
        RaiseLog(LOG_LEVEL_ERR, "IoTGpioSetFunc IOT_GPIO_FUNC_GPIO_10_I2C0_SDA failed! \n");
        return -1;
    }

    // GPIO_9复用为I2C0_SCL
    if (IoTGpioSetFunc(FLOWER_MOTOR_GPIO_9, IOT_GPIO_FUNC_GPIO_9_I2C0_SCL) != 0) {
        RaiseLog(LOG_LEVEL_ERR, "IoTGpioSetFunc IOT_GPIO_FUNC_GPIO_9_I2C0_SCL failed! \n");
        return -1;
    }
    // baudrate: 400kbps
    if (IoTI2cInit(WIFI_IOT_I2C_IDX_0, 400000) != 0) {
        RaiseLog(LOG_LEVEL_ERR, "IoTI2cInit failed! \n");
        return -1;
    }
    if (Init_SHT30() != 0) {
        RaiseLog(LOG_LEVEL_ERR, "Init_SHT30 failed! \n");
        return -1;
    }
    return 0;
}

static int InitSoilSensor()
{
    return 0;
}

int FlowerInit(void)
{
    if (InitMotor() < 0) {
        RaiseLog(LOG_LEVEL_ERR, "InitMotor failed! \n");
        
        return -1;
    }
    if (InitAirSensor() < 0) {
        RaiseLog(LOG_LEVEL_ERR, "InitAirSensor failed! \n");
        return -1;
    }
    if (InitSoilSensor() < 0) {
        RaiseLog(LOG_LEVEL_ERR, "InitSoilSensor failed! \n");
        return -1;
    }
    

    return 0;
}

int FlowerSetMotorStatus(int status)
{
    if (status == CN_BOARD_SWITCH_ON) {
        IoTGpioSetOutputVal(FLOWER_MOTOR_GPIO_5,IOT_GPIO_VALUE0);
        printf("抽水机开启!\n");
    } else {
        IoTGpioSetOutputVal(FLOWER_MOTOR_GPIO_5,IOT_GPIO_VALUE1);
         printf("抽水机关闭!\n");
    }

    return 0;
}

int FlowerGetAirStatus(int *temperature, int *humidity, int *lux)
{
    int ret = -1;
    uint8_t data[3];
    uint16_t dat, tmp;
    uint8_t SHT3X_Data_Buffer[6];
    
    int rets;
    float intensity;
    rets = StartBH1750();
    if (rets != 0) {
        printf("Start BH1750 failed!\r\n");
        return -1;
    }
    usleep(180000);
    uint8_t recv_data[2] = {0};
    rets = IoTI2cRead(WIFI_IOT_I2C_IDX_1, (BH1750_ADDR << 1) | 0x01, recv_data, 2);
    if (rets != 0) {
        return -1;
    }
    intensity = (float)(((recv_data[0] << 8) + recv_data[1]) / 1.2);
    *lux = (int) intensity;

    IotI2cData sht30_i2c_data = {0};
    uint8_t send_data[2] = {0xE0, 0x00};
    
    sht30_i2c_data.sendBuf = send_data;
    sht30_i2c_data.sendLen = 2;
    sht30_i2c_data.receiveBuf = SHT3X_Data_Buffer;
    sht30_i2c_data.receiveLen = 6;
    IoTI2cWriteread(WIFI_IOT_I2C_IDX_0, (SHT30_Addr << 1) | 0x00, &sht30_i2c_data);

    data[0] = SHT3X_Data_Buffer[0];
    data[1] = SHT3X_Data_Buffer[1];
    data[2] = SHT3X_Data_Buffer[2];

    tmp = SHT3x_CheckCrc(data, 2, data[2]);
    if (!tmp) {
        dat = ((uint16_t)data[0] << 8) | data[1];
        *temperature = SHT3x_CalcTemperatureC(dat);
    }

    data[0] = SHT3X_Data_Buffer[3];
    data[1] = SHT3X_Data_Buffer[4];
    data[2] = SHT3X_Data_Buffer[5];

    tmp = SHT3x_CheckCrc(data, 2, data[2]);
    if (!tmp) {
        dat = ((uint16_t)data[0] << 8) | data[1];
        *humidity = SHT3x_CalcRH(dat);
        ret = 0;
    }

    return ret;
}
/***************************************************************
* 说    明:获取土壤湿度
***************************************************************/
int FlowerGetSoilStatus(int *moisture)
{
    int ret = -1;
    unsigned short adc;

    ret = IoTAdcRead(IOT_ADC_CHANNEL_6, &adc, IOT_ADC_EQU_MODEL_8, IOT_ADC_CUR_BAIS_DEFAULT, 0xff);
    if (ret == IOT_SUCCESS) {
        *moisture = (int)((float)adc/1500*100);
        ret = 0;
    }

    return ret;
}

/***************************************************************
* 函数名称: E53IA1_SetFanStatus
* 说    明: 启动E53IA1_SetFanStatus
* 参    数: int status, int speedLevel
* 返 回 值: speedLevel //电机转速
***************************************************************/
int E53IA1_SetFanStatus(int state, int speedLevel)
{
    int ret = 0;
    int pwmDutyCycle = 0;
    if (state == CN_BOARD_SWITCH_ON) {
        switch (speedLevel) {
             case FAN_SPEED_LEVEL_0:
            IoTPwmStop(CN_MAIN_FAN_PWM1OUT);
                break;
            case FAN_SPEED_LEVEL_1:
                pwmDutyCycle = 10;
                break;
            case FAN_SPEED_LEVEL_2:
                pwmDutyCycle = 40;
                break;
            case FAN_SPEED_LEVEL_3:
                pwmDutyCycle = 70;
                break;
            case FAN_SPEED_LEVEL_4:
                pwmDutyCycle = 99;
                break;
            default:
                break;
        }
        ret = IoTPwmStart(CN_MAIN_FAN_PWM1OUT, pwmDutyCycle, CN_MAIN_FAN_FRE);
    } else {
        ret = IoTPwmStop(CN_MAIN_FAN_PWM1OUT);
    }

    RaiseLog(LOG_LEVEL_INFO, "state=%d, speedLevel=%d, ret = %d", state, speedLevel, ret);

    return 0;
}

void FlowerDeinit(void)
{
}
